#include "voc.pascal.Data.h"

using namespace voc_pascal;

CAnnotationFileConfig CImageGtInfo::AnnotationFileConfig;

void CAnnotationInfo::SetAnnotationInfo(
	CClassSet* pClassSet, const string& ClassName,
	const string& strAspect,
	const string& strIsTruncated,
	const string& strIsDifficult
	)
{
	ClassInfo.myInit_ByName(pClassSet, ClassName);
	this->strAspect = strAspect;
	this->strIsTruncated = strIsTruncated;
	this->strIsDifficult = strIsDifficult;
	CDataStructureTools::ToLowerCase(this->strAspect);
	CDataStructureTools::ToLowerCase(this->strIsTruncated);
	CDataStructureTools::ToLowerCase(this->strIsDifficult);
}

bool CGroundTruthItem::InputFromStream(istream& inStream, CClassSet* pClassSet)
{
	string st;
	return InputFromStream(inStream, pClassSet, st);
}

bool CGroundTruthItem::InputFromStream(istream& inStream, CClassSet* pClassSet, string& strTitle)
{
	string s1,s2,s3,s4;
	if (!(inStream>>strTitle>>s1>>s2>>s3>>s4)) return false;
	SetAnnotationInfo(pClassSet, s1, s2, s3, s4);
	return TightBox.InputFromStream(inStream) && LooseBox.InputFromStream(inStream);
}

void CGroundTruthItem::OutputToStream(ostream& outStream, const string& strTitle) const
{
	string st;
	if (strTitle == "") st = "*"; else st = strTitle;
	outStream<<st<<'\t';
	outStream<<ClassInfo.GetData().Name<<'\t';
	outStream<<strAspect<<'\t';
	outStream<<strIsTruncated<<'\t';
	outStream<<strIsDifficult<<'\t';
	TightBox.OutputToStream(outStream, false);
	LooseBox.OutputToStream(outStream);
}

bool CTargetConfig::Check(const CAnnotationInfo* pAnnotationInfo) const
{
	bool ret = true;

	ret &= (ClassInfo.Index == pAnnotationInfo->ClassInfo.Index);
	ret &= (strAspect=="*" || strAspect==pAnnotationInfo->strAspect);
	ret &= (strIsTruncated=="*" || strIsTruncated==pAnnotationInfo->strIsTruncated);
	ret &= (strIsDifficult=="*" || strIsDifficult==pAnnotationInfo->strIsDifficult);

	return ret;
}

void CImageGtInfo::myInit_2006(const string& strFN_TXT_Annotation, CClassSet* pClassSet)
{
	ifstream inFile(strFN_TXT_Annotation.c_str());
	int i,j;
	string st;
	char s0[10001];
	char ct;
	string scn;
	string sa;
	string strunc;
	string sdiffc;

	for ( st[0] = 0; st!="size"; inFile>>st );
	for ( st[0] = 0; st!=":"; inFile>>st );
	inFile>>W>>st>>H;

	CGroundTruthItem tgti;

	GtItemList.Clear();
	for ( ; ; )
	{
		strcpy(s0,st.c_str()); if (!(inFile>>st)) break;
		if (st != "(Xmin,") continue;
		if (s0[strlen(s0)-1]=='\"') s0[strlen(s0)-1] = 0;
		for ( i = 4; s0[i]; ++i ) if (s0[i]>='A' && s0[i]<='Z') break;
		ct = s0[i]; s0[i] = 0; scn = s0+4; s0[i] = ct;
		sa = "Unspecified"; strunc = "0"; sdiffc = "0";
		for ( ; s0[i]; )
		{
			j = i; for ( ++i; s0[i]; ++i ) if (s0[i]>='A' && s0[i]<='Z') break;
			ct = s0[i]; s0[i] = 0; st = s0+j; s0[i] = ct;
			if (st == "Trunc")
				strunc = "1";
			else if (st == "Difficult")
				sdiffc = "1";
			else
				sa = st;
		}
		tgti.SetAnnotationInfo(pClassSet, scn, sa, strunc, sdiffc);

		for ( st[0] = 0; st!=":"; inFile>>st );
		for ( ct = 0; ct!='('; inFile>>ct );
		inFile>>tgti.TightBox.x;
		for ( ct = 0; ct!=','; inFile>>ct );
		inFile>>tgti.TightBox.y;
		for ( ct = 0; ct!='('; inFile>>ct );
		inFile>>tgti.TightBox.w;
		for ( ct = 0; ct!=','; inFile>>ct );
		inFile>>tgti.TightBox.h;
		--tgti.TightBox.x;
		--tgti.TightBox.y;
		tgti.TightBox.w -= tgti.TightBox.x;
		tgti.TightBox.h -= tgti.TightBox.y;

		GtItemList.PushBack(tgti);
	}

	inFile.clear();
	inFile.close();

	for ( i = 0; i < GtItemList.Size; ++i )
	{
		CRectBox<int>& tbox = GtItemList.pElement[i].TightBox;
		tbox.MakeBounded(0,0,1,1,W,H);
	}

	fHasInstances = (GtItemList.Size > 0);
}

void CImageGtInfo::myInit_2007(const string& strFN_XML_Annotation, CClassSet* pClassSet)
{
	int i;
	CxmlTree xmlTree;
	xmlTree.myInit(strFN_XML_Annotation);

	int nid_W			= xmlTree.GetNotationID(AnnotationFileConfig.sntW);
	int nid_H			= xmlTree.GetNotationID(AnnotationFileConfig.sntH);
	int nid_Object		= xmlTree.GetNotationID(AnnotationFileConfig.sntObject);
	int nid_ClassName	= xmlTree.GetNotationID(AnnotationFileConfig.sntClassName);
	int nid_Aspect		= xmlTree.GetNotationID(AnnotationFileConfig.sntAspect);
	int nid_IsTruncated	= xmlTree.GetNotationID(AnnotationFileConfig.sntIsTruncated);
	int nid_IsDifficult	= xmlTree.GetNotationID(AnnotationFileConfig.sntIsDifficult);
	int nid_Box			= xmlTree.GetNotationID(AnnotationFileConfig.sntBox);
	int nid_XMin		= xmlTree.GetNotationID(AnnotationFileConfig.sntXMin);
	int nid_XMax		= xmlTree.GetNotationID(AnnotationFileConfig.sntXMax);
	int nid_YMin		= xmlTree.GetNotationID(AnnotationFileConfig.sntYMin);
	int nid_YMax		= xmlTree.GetNotationID(AnnotationFileConfig.sntYMax);

	CxmlTreeNode* pnI;
	CxmlTreeNode* pnA;
	CxmlTreeNode* pnB;
	CGroundTruthItem tGtItem;
	string scn,sa,st,sd;
	
	GtItemList.Clear();
	W = H = -1;
	for ( pnI = xmlTree.GetFirstNode_PreorderTraversal(); pnI; pnI = pnI->GetNextNode_PreorderTraversal() )
	{
		if (pnI->NotationID == nid_W)
		{
			W = (int)(atof(pnI->strContent.c_str()) + EPS);
			continue;
		}
		if (pnI->NotationID == nid_H)
		{
			H = (int)(atof(pnI->strContent.c_str()) + EPS);
			continue;
		}

		if (pnI->NotationID != nid_Object) continue;

		pnA = pnI->GetNextChildWithNotation(nid_ClassName);		if (!pnA) continue;		
		scn = pnA->strContent.c_str();
		pnA = pnI->GetNextChildWithNotation(nid_Aspect);
		sa = (pnA ? pnA->strContent.c_str() : "*");
		pnA = pnI->GetNextChildWithNotation(nid_IsTruncated);
		st = (pnA ? pnA->strContent.c_str() : "*");
		pnA = pnI->GetNextChildWithNotation(nid_IsDifficult);
		sd = (pnA ? pnA->strContent.c_str() : "*");

		pnA = pnI->GetNextChildWithNotation(nid_Box);			if (!pnA) continue;		
		pnB = pnA->GetNextChildWithNotation(nid_XMin);			if (!pnB) continue;
		tGtItem.TightBox.x = (int)(atof(pnB->strContent.c_str()) + EPS) - 1;
		pnB = pnA->GetNextChildWithNotation(nid_XMax);			if (!pnB) continue;
		tGtItem.TightBox.w = (int)(atof(pnB->strContent.c_str()) + EPS) - tGtItem.TightBox.x;
		pnB = pnA->GetNextChildWithNotation(nid_YMin);			if (!pnB) continue;
		tGtItem.TightBox.y = (int)(atof(pnB->strContent.c_str()) + EPS) - 1;
		pnB = pnA->GetNextChildWithNotation(nid_YMax);			if (!pnB) continue;
		tGtItem.TightBox.h = (int)(atof(pnB->strContent.c_str()) + EPS) - tGtItem.TightBox.y;

		tGtItem.SetAnnotationInfo(pClassSet, scn, sa, st, sd);
		GtItemList.PushBack(tGtItem);
	}

	if (W<=0 || H<=0)
	{
		W = H = 0;
		GtItemList.Clear();
		return;
	}

	for ( i = 0; i < GtItemList.Size; ++i )
	{
		CRectBox<int>& tbox = GtItemList.pElement[i].TightBox;
		tbox.MakeBounded(0,0,1,1,W,H);
	}

	fHasInstances = (GtItemList.Size > 0);
}

bool CImageGtInfo::InputFromStream(istream& inStream, CClassSet* pClassSet)
{
	bool ret;
	int i,s;

	if ((inStream>>strImageTitle>>W>>H>>s) && W>=0 && H>=0)
	{
		GtItemList.Resize(s);
		for ( i = 0; i < s; ++i )
			if (!GtItemList.pElement[i].InputFromStream(inStream, pClassSet))
				break;
		ret = (i >= s);
	}
	else
		ret = false;
	if (!ret)
	{
		W = H = 0;
		GtItemList.Resize(0);
	}

	fHasInstances = (GtItemList.Size > 0);

	return ret;
}

void CImageGtInfo::OutputToStream(ostream& outStream)
{
	int i;
	outStream<<strImageTitle<<" "<<W<<" "<<H<<" "<<GtItemList.Size<<endl;
	for ( i = 0; i < GtItemList.Size; ++i )
		GtItemList.pElement[i].OutputToStream(outStream, strImageTitle);
}

bool CImageGtInfoSet::InputFromFile(const string& strFN_ImageGtInfoSet, CClassSet* pClassSet)
{
	int i,s;

	ifstream inFile(strFN_ImageGtInfoSet.c_str());
	inFile>>s;
	igtList.Resize(s);
	for ( i = 0; i < s; ++i )
		if (!(igtList.pElement[i].InputFromStream(inFile, pClassSet)))
		{
			igtList.Resize(s = i);
			break;
		}
	inFile.clear();
	inFile.close();

	InitMapping();

	return true;
}

void CImageGtInfoSet::OutputToFile(const string& strFN_ImageGtInfoSet)
{
	int i;

	ofstream outFile(strFN_ImageGtInfoSet.c_str());
	outFile<<igtList.Size<<endl;
	for ( i = 0; i < igtList.Size; ++i )
		igtList.pElement[i].OutputToStream(outFile);
	outFile.clear();
	outFile.close();
}

void CImageGtInfoSet::InitMapping()
{
	int i;

	it2index.clear();
	for ( i = 0; i < igtList.Size; ++i )
		it2index[igtList.pElement[i].strImageTitle] = i;
}

int CImageGtInfoSet::GetImageGtInfo(CImageGtInfo& DstIGT, const string& strImageTitle) const
{
	map<string, int>::const_iterator itr;
	itr = it2index.find(strImageTitle);
	if (itr == it2index.end())
		return -1;
	else
	{
		DstIGT = igtList.pElement[itr->second];
		return itr->second;
	}
}

const CImageGtInfo& CImageGtInfoSet::GetImageGtInfo(const string& strImageTitle) const
{
	map<string, int>::const_iterator itr;
	itr = it2index.find(strImageTitle);
	if (itr == it2index.end())
		return igtList.pElement[0];
	else
		return igtList.pElement[itr->second];
}

bool CBoxExample::InputFromStream(istream& inStream, const CFileNameList& FileNameList)
{
	int flag;
	string st;

	if (!(inStream>>flag)) return false;
	fIsPos = (flag==1);
	if (!(inStream>>st)) return false;
	ImageIndex = FileNameList.GetFileIndex(st);
	if (ImageIndex<0) return false;
	if (!(inStream>>InitialWeight)) return false;
	if (!(inStream>>Box.x>>Box.y>>Box.w>>Box.h)) return false;
	return true;
}

void CBoxExample::OutputToStream(ostream& outStream, const CFileNameList& FileNameList) const
{
	outStream<<(fIsPos ? "+1" : "-1")<<'\t';
	outStream<<FileNameList.rgFN_Main[ImageIndex]<<'\t';
	outStream.precision(8);
	outStream<<fixed<<InitialWeight<<'\t';
	outStream<<Box.x<<'\t';
	outStream<<Box.y<<'\t';
	outStream<<Box.w<<'\t';
	outStream<<Box.h<<endl;
}

void CDataSet_VocPascal_ByImage::myRelease()
{
	int i;

	for ( i = 0; i < _IBFE_Pool.Size; ++i )
		delete _IBFE_Pool.pElement[i];
	_IBFE_Pool.Resize(0);
}

CDataSet_VocPascal_ByImage::CDataSet_VocPascal_ByImage()
{
	_pCacheManager = new CRandomCacheManager;
	_IBFE_Pool.Clear();

	NodeList.Clear();
}

CDataSet_VocPascal_ByImage::~CDataSet_VocPascal_ByImage()
{
	delete _pCacheManager;
	myRelease();
}

void CDataSet_VocPascal_ByImage::InitFeatureSettings(int ImagePoolSize, CFileNameList* pFileNameList)
{
	_pFileNameList = pFileNameList;
	int i;
	
	myRelease();
	_IBFE_Pool.Resize(ImagePoolSize);
	for ( i = 0; i < ImagePoolSize; ++i )
		_IBFE_Pool.pElement[i] = CIBFE_Factory::GetNewIBFE();
	_pCacheManager->myInit(ImagePoolSize, _pFileNameList->FileAmount);
}

void CDataSet_VocPascal_ByImage::InputNodeListFromFile(const string& strFN_NodeList, const CFileNameList& FileNameList)
{
	int i;

	ifstream inFile(strFN_NodeList.c_str());

	inFile>>i;
	NodeList.Resize(i);
	for ( i = 0; i < NodeList.Size; ++i )
		NodeList.pElement[i].InputFromStream(inFile, FileNameList);

	inFile.clear();
	inFile.close();
}

void CDataSet_VocPascal_ByImage::OutputNodeListToStream(ostream& outStream, const CFileNameList& FileNameList) const
{
	int i;

	outStream<<NodeList.Size<<endl;
	for ( i = 0; i < NodeList.Size; ++i )
		NodeList.pElement[i].OutputToStream(outStream, FileNameList);
}

void CDataSet_VocPascal_ByImage::OutputNodeListToFile(const string& strFN_NodeList, const CFileNameList& FileNameList) const
{
	ofstream outFile(strFN_NodeList.c_str());
	OutputNodeListToStream(outFile, FileNameList);
	outFile.clear();
	outFile.close();
}

int CDataSet_VocPascal_ByImage::GetNodeAmount()
{
	return (int)NodeList.Size;
}

double CDataSet_VocPascal_ByImage::GetNodeInitialWeight(int NodeIndex)
{
	if (NodeIndex<0 || NodeIndex>=NodeList.Size)
		return 0.0;
	else
		return NodeList.pElement[NodeIndex].InitialWeight;
}

int CDataSet_VocPascal_ByImage::GetFeatureDim()
{
	if (_IBFE_Pool.Size > 0)
		return (*_IBFE_Pool.pElement)->GetFeatureDim();
	else
		return 0;
}

double CDataSet_VocPascal_ByImage::GetNodeFeature(int NodeIndex, int FeatureIndex)
{
	CImageBoxFeatureExtractor* pIBFE;
	__int64 CurrentImageIndex, LastImageIndex;

	if (NodeIndex<0 || NodeIndex>=NodeList.Size)
		return 0.0;
	CurrentImageIndex = NodeList.pElement[NodeIndex].ImageIndex;
	pIBFE = _IBFE_Pool.pElement[_pCacheManager->GetItemPosition(CurrentImageIndex, LastImageIndex)];
	if (CurrentImageIndex != LastImageIndex)
	{
		CRichImage SrcRichImage;
		SrcRichImage.LoadImageByFileName(_pFileNameList->rgFN_SrcImage[(size_t)CurrentImageIndex]);
		pIBFE->SetImage(SrcRichImage);

	}
	return pIBFE->GetFeature(NodeList.pElement[NodeIndex].Box, FeatureIndex);
}

int CDataSet_VocPascal_ByImage::GetNodeFlag(int NodeIndex)
{
	if (NodeIndex<0 || NodeIndex>=NodeList.Size)
		return 0;
	else
		return (NodeList.pElement[NodeIndex].fIsPos ? +1 : -1);
}

